package org.lib.mysqlhello.security;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.lib.mysqlhello.security.self.AppUser;
import org.lib.mysqlhello.security.self.AppUserDAO;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;

import lombok.extern.slf4j.Slf4j;

/**
 * 密码加密算法升级（2）
 * @author ben
 * @date 2021-09-07 13:52:07 CST
 */
@Slf4j
public class UpgradePasswordEncoder2 implements PasswordEncoder {
	
	public static final String ENCODER_ID = "Pbkdf2";
	
	public UpgradePasswordEncoder2(AppUserDAO appUserDao, HttpServletRequest req) {
		this.appUserDao = appUserDao;
		this.req = req;
	}
	
	// 旧加密算法
	private BCryptPasswordEncoder oldEncoder = new BCryptPasswordEncoder(12);
	
	// newEncoder 不能使用 DelegatingPasswordEncoder！matches会匹配异常！
//	private static DelegatingPasswordEncoder newEncoder = (DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
	private Pbkdf2PasswordEncoder newEncoder = new Pbkdf2PasswordEncoder();

	private AppUserDAO appUserDao;
	
	private HttpServletRequest req;
	
	@Override
	public String encode(CharSequence rawPassword) {
		return newEncoder.encode(rawPassword);
	}

	@Override
	public boolean matches(CharSequence rawPassword, String encodedPassword) {
		if (rawPassword == null) {
			throw new IllegalArgumentException("rawPassword cannot be null");
		}
		if (encodedPassword == null || encodedPassword.length() == 0) {
			return false;
		}
		
		// 这里的 encodedPassword 是没有前缀的！
		if (oldEncoder.matches(rawPassword, encodedPassword)) {
			// 怎么获取用户并更新？用户ID哪里找？TODO
			// 根据session去获取用户信息？TODO
			String username = req.getParameter("username");
			log.info("旧密码算法匹配成功：username={}", username);
			// 旧密码 匹配成功！
			// 更新数据库
			AppUser user = appUserDao.findByUsername(username);
			// 加前缀！
			String newPassword = "{" + ENCODER_ID + "}" + this.encode(rawPassword);
			user.setPassword(newPassword);
			appUserDao.save(user);
			log.warn("升级了用户密码加密算法：username={}", username);
			return true;
		}
		
		// 嵌套到 DelegatingPasswordEncoder 中使用时，这里的 encodedPassword 没有前缀，会导致匹配失败！
		if (newEncoder.matches(rawPassword, encodedPassword)) {
			// 新密码匹配成功
			String username = req.getParameter("username");
			log.info("新密码算法匹配成功：username={}", username);
			return true;
		}
		
		// 新旧密码算法都匹配失败，登录失败
		return false;
	}
	
}
